home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / System 7.0 Samples / AEObject-Edition1.0.2 Sample / AEObject.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-18  |  79.7 KB  |  1,780 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. *
  3. *  Apple Developer Technical Support
  4. *
  5. *  AppleEvent™ Object Model and Object Support Library routines
  6. *
  7. *  Program:AEObject-Edition Sample
  8. *  File: AEObject.c -C Source
  9. *
  10. *  by:   C.K. Haun <TR>
  11. *
  12. *  Copyright © 1991,1992 Apple Computer, Inc.
  13. *  All rights reserved.
  14. *
  15. *------------------------------------------------------------------------------
  16. * This file contains most of the routines that deal with AppleEvent Objects, and
  17. * the routines that use them.
  18. * Object resolution, and Object accessors play a large part here.  Once you under-
  19. * stand and have written a few accessors, you'll see that this stuff becomes a great
  20. * deal easier.
  21. * vers 1.0.1- All AE constants changed to reflect Winter '92 registry 
  22. *----------------------------------------------------------------------------*/
  23. /* And another Note:
  24. * I am resolving simple objects in this file and sample.  I intend to
  25. * go on to complex objects in a future sample, please stay tuned */
  26.  
  27. /* Some words about the objects and handlers */
  28. /* Windows */
  29. /* When a window is asked for or used, the token I create is an AEDesc */
  30. /* of type cWindow, and the data associated with this is  */
  31. /* (suprisingly enough) a window pointer.  In this sample I can do anything */
  32. /* with my data based on a window pointer. */
  33. /* The rest of the tokens are AEDescs containing structures in the dataHandle, */
  34. /* please see the AESampStructs.h file for the definition of these structures */
  35. /* ••• Remember ---  A token can be anything you like. It does NOT get passed outside */
  36. /* your application, it only stays inside it.   */
  37. #define __AEOBJ__
  38.  
  39. #include "Sampdefines.h"
  40.  
  41. #pragma segment MyInit
  42.  
  43. /* InstallObjectHandlers normally would be in the Initialize.c file, but I wanted to put it here, */
  44. /* along with the rest of the Object Model code so you could see everything in one place */
  45.  
  46. /* This routine starts the ObjectSupportLibrary, and installs all the callbacks and  */
  47. /* object accessors for this program. */
  48. OSErr InstallObjectHandlers(void)
  49. {
  50.     /* Initialize the library.  This makes some internal calls to the AppleEvent manager */
  51.     OSErr myErr = AEObjectInit();
  52.     if (!myErr) {
  53.         /* The meat of the initialization.  Here I'm installing all the object accessors */
  54.         /* I've written.  These are the routines that the OSL will call when I call */
  55.         /* AEResolve on an object in an AppleEvent.  These routines do all the  */
  56.         /* parsing of the object specifier, segment by segment.  Each of them returns a */
  57.         /* token that describes the in-memory structure of the object specified in a way */
  58.         /* my application can understand.  No one else will ever see these tokens */
  59.         /* they are ONLY for use inside my program.  This means that they can be anything that */
  60.         /* makes sense to me and my appliction. */
  61.         /* The actual token structures I use are defined in the AESampStructs.h file. */
  62.         /* This accessor returns a window token from a null descriptor.  This  */
  63.         /* accessor will be called a LOT, since specifing anything in my application */
  64.         /* will usually reference an owning window. */
  65.         
  66.         myErr = AEInstallObjectAccessor(cWindow, typeNull, NewOSLAccessorProc(WindFromNull), 0, false);
  67.         
  68.         /* This accessor gets ANY property from a window token */
  69.         /* Since a window token describes all the important junk about the window */
  70.         /* I only need one property from window accessor */
  71.         
  72.         myErr = AEInstallObjectAccessor(typeProperty, cWindow, NewOSLAccessorProc(PropertyFromWindow), 0, false);
  73.         
  74.         /* This installs my Text from Window accessor.  If there is a text object in this window */
  75.         /* this routine will return a token for it */
  76.         
  77.         myErr = AEInstallObjectAccessor(cText, cWindow, NewOSLAccessorProc(TextFromWindow), 0, false);
  78.         
  79.         /* Now be able to pass back properties of my Text objects */
  80.         
  81.         myErr = AEInstallObjectAccessor(typeProperty, cText, NewOSLAccessorProc(PropertyFromText), 0, false);
  82.         
  83.         /* This installs my Word from Text accessor. */
  84.         
  85.         myErr = AEInstallObjectAccessor(cWord, cText, NewOSLAccessorProc(WordFromText), 0, false);
  86.         
  87.         myErr = AEInstallObjectAccessor(cDrawingArea, cWindow, NewOSLAccessorProc(DrawFromWindow), 0, false);
  88.         
  89.         /* This guy graps a graphic shape from my window, no matter what it actually is */
  90.         
  91.         myErr = AEInstallObjectAccessor(cGraphicShape, cDrawingArea, NewOSLAccessorProc(ShapeFromDraw), 0, false);
  92.         myErr = AEInstallObjectAccessor(cGraphicShape, cWindow, NewOSLAccessorProc(ShapeFromDraw), 0, false);
  93.         /* these grab specific shapes from the drawing area */
  94.         /* The canny observer will notice that these all call the ShapeFromDraw routine */
  95.         /* Since my shapes are all defined in the same type of structure, this makes  */
  96.         /* a lot of sense for me */
  97.                 
  98.         myErr = AEInstallObjectAccessor(cGraphicLine, cDrawingArea, NewOSLAccessorProc(ShapeFromDraw), 0, false);
  99.         myErr = AEInstallObjectAccessor(cOval, cDrawingArea, NewOSLAccessorProc(ShapeFromDraw), 0, false);
  100.         myErr = AEInstallObjectAccessor(cRectangle, cDrawingArea, NewOSLAccessorProc(ShapeFromDraw), 0, false);
  101.         myErr = AEInstallObjectAccessor(cGraphicLine, cWindow, NewOSLAccessorProc(ShapeFromDraw), 0, false);
  102.         myErr = AEInstallObjectAccessor(cOval, cWindow, NewOSLAccessorProc(ShapeFromDraw), 0, false);
  103.         myErr = AEInstallObjectAccessor(cRectangle, cWindow, NewOSLAccessorProc(ShapeFromDraw), 0, false);
  104.  
  105.         /* and the same type o' thing for shape properties */
  106.         myErr = AEInstallObjectAccessor(typeProperty, cGraphicLine, NewOSLAccessorProc(PropertyFromShape), 0, false);
  107.         myErr = AEInstallObjectAccessor(typeProperty, cOval, NewOSLAccessorProc(PropertyFromShape), 0, false);
  108.         myErr = AEInstallObjectAccessor(typeProperty, cRectangle, NewOSLAccessorProc(PropertyFromShape), 0, false);
  109.  
  110.  
  111.         
  112.         /* And the list will go on and on.  Once you've written a few accessors, you realize  */
  113.         /* how handy they are, and you start installing them for everything that can  */
  114.         /* possibly be gotten from anything else.  The only limit will be the  */
  115.         /* amount of code space you want to dedicate to accessors. */
  116.         /* Remember, the more accessors you put in, the more ways users will have to */
  117.         /* get at your data, and the less they will have to learn or remember. */
  118.         /* Our goal, as always, is to make it as easy for the user as possible. */
  119.         /* I will also use the same routine to go from a null */
  120.         
  121.         /* Here I am installing all the call back routines that the OSL needs.  */
  122.         /* These are not all implemented as doing something, but they will eventually */
  123.         /* These tokens will be called by the OSL as it does it's parsing  */
  124.         /* thrugh a passed object specifier. */
  125.         /* You may not need all of these, any you don't need just pass */
  126.         /* a nil */
  127.         
  128.         myErr = AESetObjectCallbacks(NULL, 
  129.             NewOSLCountProc(MyCountProc), 
  130.             NewOSLDisposeTokenProc(MyDisposeTokenProc),
  131.             NULL, NULL, NULL, NULL);
  132.         
  133.     }
  134.     return(myErr);
  135. }
  136.  
  137.  
  138. #pragma segment AEOSL
  139. /* My GetData event handler.  This routine resolves the object passed (calling AEResolve) */
  140. /* and then returns the appropriate data to the sender of the event */
  141. pascal OSErr AEGetDataHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  142. {
  143.  #pragma unused (refIn)
  144.  
  145.     OSErr myErr = noErr;
  146.     AEDesc tokenBack;
  147.     AEDesc theObject;
  148.     AEDesc returnDesc;
  149.     /* variables for the various tokens I'll be getting back */
  150.     CWordObjHandle wordToken;
  151.     CTextObjHandle textToken;
  152.     PropertyTHdl propertyToken;
  153.     Handle myDataHandle, tempHandle;
  154.     Size dataSize;
  155.     /* window is just a window ptr */
  156.     gCurrentReply = reply;
  157.     mVerboseOutput("\p\nEntering GetData handler")
  158.     myErr = AEGetParamDesc(messagein, keyDirectObject, typeObjectSpecifier, &theObject);
  159.         mAEErrorDisplay("\p getting object spec", myErr)
  160.     if (!myErr) {
  161.         returnDesc.descriptorType = typeNull;               /* set this up for a later check */
  162.         myErr = AEResolve(&theObject, kAEIDoMinimum, &tokenBack);
  163.         mAEErrorDisplay("\p AEResolve", myErr)
  164.         
  165.         if (!myErr) {
  166.             /* Hey, marvy, we got an object token back.  That means that we have  */
  167.             /*  enough information to derive the data. */
  168.             /* Again, and forever, we don't care how you actually access data and create tokens */
  169.             /* inside your application, you know how to do that much bettern than we ever will. */
  170.             /* As long as it makes sense, and is efficient, for you, it's fine with us. */
  171.             /* I am going to have to do some switching and stuff here to put the data I got into the reply */
  172.             
  173.             /* By the Way:  You could make all your tokens with the same field for the  */
  174.             /* data and descriptor type.  If you did that, you wouldn't need the case */
  175.             /* here for a GetData event, you would just pass back what you got. */
  176.             /* I thought about it for this sample, but it seems more descriptive to */
  177.             /* go through the specific objects.  I may change my mind.... */
  178.             
  179.             /* Anyway, I switch off the type of token I got back... */
  180.             switch (tokenBack.descriptorType) {
  181.                 case cWindow:
  182.                     /* for this, I'm going to pass back the Window ID I use in this program. */
  183.                     /* Why not the window pointer?  Because we don't have shared memory in the current */
  184.                     /* Mac OS, so I don't want people mucking around in my windows directly. */
  185.                     /* And really, if you're getting a request for a bare window, all the other side */
  186.                     /* is probably trying to see is if a window exisits.  I hope. */
  187.                     /* they can pass back this as a selector for NewElement, or something */
  188.                     /* You won't see this for a GetData much, in fact you can't from this  */
  189.                     /* sample get it.  I mean it ain't in the GetData menu */
  190.                     
  191.                     break;
  192.                 case cText:
  193.                     /* Pass back the chunk o' text.  Since I'm using TextEdit, I know that I'll */
  194.                     /* never be over 32k here.  Keep in mind that the AppleEvent manager can only */
  195.                     /* handle data up to 64k, so if you are passing back more text (or whatever) */
  196.                     /* than that you'll have to do it in a series of returns, or pass back an */
  197.                     /* alias to a file, or some such. */
  198.                     textToken = (CTextObjHandle)tokenBack.dataHandle;
  199.                     myDataHandle = (Handle)TEGetText((*textToken)->theText);
  200.                     HLock(myDataHandle);
  201.                     dataSize = GetHandleSize(myDataHandle);
  202.                     /* again, this check is not really necessary, but I want to put it here */
  203.                     /* as a warning, and maybe someday I'll stop using TextEdit. */
  204.                     if (dataSize > k64k) {
  205.                         /* if this were true, you would have to do something. */
  206.                         dataSize = k64k;
  207.                     }
  208.                     myErr = AECreateDesc(typeChar, (Ptr)*myDataHandle, dataSize, &returnDesc);
  209.                     HUnlock(myDataHandle);
  210.                     /* and kill the remaining token */
  211.                     myErr = MyDisposeTokenProc(&tokenBack);
  212.                     /* the descriptor will be added to the reply later in this function */
  213.                     break;
  214.                 case cWord:
  215.                     /* same basic thing for a word as for a text */
  216.                     wordToken = (CWordObjHandle)tokenBack.dataHandle;
  217.                     myDataHandle = NewHandle((*wordToken)->endPos - (*wordToken)->startPos);
  218.                     HLock(myDataHandle);
  219.                     dataSize = GetHandleSize(myDataHandle);
  220.                     /* move the text from the te chars handle to my data handle */
  221.                     tempHandle = (Handle)TEGetText((*wordToken)->theText);
  222.                     HLock(tempHandle);
  223.                     BlockMove((Ptr)(*tempHandle + (*wordToken)->startPos), (Ptr)*myDataHandle, dataSize);
  224.                     HUnlock(tempHandle);
  225.                     /* again, this check is not really necessary, but I want to put it here */
  226.                     /* as a warning. */
  227.                     if (dataSize > k64k) {
  228.                         /* if this were true, you would have to do something. */
  229.                         dataSize = k64k;
  230.                     }
  231.                     myErr = AECreateDesc(typeChar, (Ptr)*myDataHandle, dataSize, &returnDesc);
  232.                     HUnlock(myDataHandle);
  233.                     /* return value will be added to reply later in this function */
  234.                     /* and kill the remaining token */
  235.                     myErr = MyDisposeTokenProc(&tokenBack);
  236.                     
  237.                     break;
  238.                 case typeProperty:
  239.                     /* just return the property as the type included in the token */
  240.                     /* The SetData handler (as you will see) needs to do a lot more */
  241.                     propertyToken = (PropertyTHdl)tokenBack.dataHandle;
  242.                     HLock((Handle)propertyToken);
  243.                     myDataHandle = (*propertyToken)->theData;
  244.                     dataSize = GetHandleSize(myDataHandle);
  245.                     /* again, this check is not really necessary, but I want to put it here */
  246.                     /* as a warning. */
  247.                     if (dataSize > k64k) {
  248.                         /* if this were true, you would have to do something. */
  249.                         dataSize = k64k;
  250.                     }
  251.                     HLock(myDataHandle);
  252.                     myErr = AECreateDesc((*propertyToken)->theDataType, (Ptr)*myDataHandle, dataSize, &returnDesc);
  253.                     myErr = MyDisposeTokenProc(&tokenBack);
  254.                     break;
  255.                     /* and others as I add them */
  256.                 case cGraphicShape:
  257.                 case cGraphicLine:
  258.                     MakeGraphicLine((CShapeObjHandle)tokenBack.dataHandle, &returnDesc);
  259.                     myErr = MyDisposeTokenProc(&tokenBack);
  260.                     break;
  261.                 case cRectangle:
  262.                 case cOval:
  263.                     /* both of these have a default descriptor type of typeRectange, so I'll go make that */
  264.                     MakeTypeRect((CShapeObjHandle)tokenBack.dataHandle, &returnDesc);
  265.                     myErr = MyDisposeTokenProc(&tokenBack);
  266.                     break;
  267.                     
  268.             }
  269.             
  270.             /* Here I either have a good descriptor for a return value, or I have  */
  271.             /* 'null' in the type field if something went wrong. */
  272.             if (returnDesc.descriptorType == typeNull) {
  273.                 /* something bad happend, there will be no reply.   */
  274.                 /* the error is already in myErr */
  275.             } else {
  276.                 AEDesc newDesc;
  277.                 AEDesc wantType;
  278.                 OSErr tempErr;
  279.                 /* we have a good descriptor.  THere's one more thing to do, and it's */
  280.                 /* technically optional, but you should support it if you can.  That's  */
  281.                 /* seeing if the sender included a type that the wanted the data back as. */
  282.                 /* if they did, I will try and coerce my return descriptor to that type */
  283.                 /* First, is there a wantType? */
  284.                 /* I equate this to tempErr instead of myErr because it is not fatal if */
  285.                 /* this get fails, I don't want to pass this error back to the sender */
  286.  
  287.  
  288.                 tempErr = AEGetParamDesc(messagein, keyAERequestedType, typeType, &wantType);
  289.                 if (!tempErr) {
  290.                     /* there was a wantType.  Try and coerce my data to that type */
  291.                     /* If the coercion fails, I will just return my type of data.  The  */
  292.                     /* sender of this event may be able to do the coercion on their */
  293.                     /* end, perhaps they have more coercion handlers on their machine */
  294.                     /* • NOTE: DON'T assume that you can't coerce the descriptor! */
  295.                     /* i.e. don't  evaluate the wantType yourself and say */
  296.                     /* "my application doesn't know how to do that" and fail. */
  297.                     /* True, your app may not know.  But someone else on the */
  298.                     /* machine MIGHT know, and they may have installed a system */
  299.                     /* level coercion routine that will make this work even if */
  300.                     /* your application knew nothing about it.  So try the coercion */
  301.                     tempErr = AECoerceDesc(&returnDesc, (DescType)**(wantType.dataHandle), &newDesc);
  302.                     if (!tempErr) {
  303.                         AEDesc tempDesc;
  304.                         /* it coerced.  So, because of the way I'm doing this, swap */
  305.                         /* things around (kinda) */
  306.                         tempDesc = returnDesc;
  307.                         returnDesc = newDesc;
  308.                         AEDisposeDesc(&tempDesc);
  309.                     }
  310.                 }
  311.  
  312.                 myErr = AEPutParamDesc(reply, keyDirectObject, &returnDesc);
  313.                 myErr = AEDisposeDesc(&returnDesc);
  314.                 
  315.             }
  316.         }                                                   /* aeresolve error */
  317.     }                                                       /* get object */
  318.     gCurrentReply = nil;
  319.     return(myErr);
  320.     
  321. }
  322.  
  323. pascal OSErr AESetDataHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  324. {
  325. #pragma unused (refIn)
  326.     OSErr myErr = noErr;
  327.     PropertyTHdl propertyBack;
  328.     CTextObjHandle cTextBack;
  329.     CWordObjHandle cWordBack;
  330.     AEDesc tokenBack;
  331.     AEDesc theObject;
  332.     AEDesc theData;
  333.     gCurrentReply = reply;
  334.     mVerboseOutput("\p\nEntering SetData handler")
  335.     myErr = AEGetParamDesc(messagein, keyDirectObject, typeObjectSpecifier, &theObject);
  336.     
  337.     mAEErrorDisplay("\p getting object spec", myErr)
  338.     /* get the data to set now also.  If we don't have any data, we can't */
  339.     /* do this event. */
  340.     /* I'm asking for the data as typeWildCard, so no coercions will take place. */
  341.     /* I may coerce the data later, but now I want it as sent. */
  342.     myErr = AEGetParamDesc(messagein, keyAEData, typeWildCard, &theData);
  343.         mAEErrorDisplay("\p getting the data", myErr)
  344.     myErr = AEResolve(&theObject, kAEIDoMinimum, &tokenBack);
  345.         mAEErrorDisplay("\p AEResolve", myErr)
  346.     if (!myErr) {
  347.         /* we have a token telling us what the object to set is.  */
  348.         /* from that, we can do our setting */
  349.         /* How you actually implement this is again very much up to  */
  350.         /* you. This is only a simple sample, do what seems best in your application */
  351.         switch (tokenBack.descriptorType) {
  352.             case cWindow:
  353.                 /* this shouldn't ever come back, since you can't set a  */
  354.                 /* window per sé.  Look at the property switch for that stuff */
  355.                 break;
  356.             case cText:
  357.                 /* setting the text of this text token */
  358.                 /* our text token contains a TEHandle, so here's what we'll do.... */
  359.                 cTextBack = (CTextObjHandle)tokenBack.dataHandle;
  360.                 /* select all the text */
  361.                 TESetSelect(0, 32000, (*cTextBack)->theText);
  362.                 /* kill the old text */
  363.                 TEDelete((*cTextBack)->theText);
  364.                 HLock(theData.dataHandle);
  365.                 /* and set the new text */
  366.                 TESetText((Ptr)*(theData.dataHandle), GetHandleSize((theData.dataHandle)), (*cTextBack)->theText);
  367.                 HUnlock(theData.dataHandle);
  368.                 /* fìn */
  369.                 MyDisposeTokenProc(&tokenBack);
  370.                 break;
  371.             case cWord:
  372.                 /* changing this one word to something else */
  373.                 /* basically the same as setting text, our range is just delimited */
  374.                 /* setting the text of this text token */
  375.                 /* our text token contains a TEHandle, so here's what we'll do.... */
  376.                 cWordBack = (CWordObjHandle)tokenBack.dataHandle;
  377.                 /* select all the text */
  378.                 TESetSelect((*cWordBack)->startPos, (*cWordBack)->endPos, (*cWordBack)->theText);
  379.                 TEDelete((*cWordBack)->theText);
  380.                 HLock(theData.dataHandle);
  381.                 TEInsert((Ptr)*(theData.dataHandle), GetHandleSize((theData.dataHandle)), (*cWordBack)->theText);
  382.                 /* fìn */
  383.                 MyDisposeTokenProc(&tokenBack);
  384.                 break;
  385.             case typeProperty:
  386.                 propertyBack = (PropertyTHdl)tokenBack.dataHandle;
  387.                 /* since there are so many properties to set, I'll switch off  */
  388.                 /* the owner and set to that type */
  389.                 switch ((*propertyBack)->owningTokenType) {
  390.                     case cWindow:
  391.                         myErr = SetWindowProperty(propertyBack, &theData);      /* in Windows.c */
  392.                         MyDisposeTokenProc(&tokenBack);
  393.                         break;
  394.                     case cText:
  395.                     case cWord:
  396.                     /* I'm not setting text or word properties in this sample, since I'm */
  397.                     /* using plain old TextEdit (not even style) */
  398.                         myErr = errAENotModifiable;
  399.                         AddToReply("\p Text property setting not implemented",0);
  400.                         break;
  401.                     case cGraphicLine:
  402.                     case cRectangle:
  403.                     case cOval:
  404.                         myErr = SetShapeProperty(propertyBack, &theData);      /* in Windows.c */
  405.                         MyDisposeTokenProc(&tokenBack);
  406.                     break;
  407.                     
  408.                     case typeProperty:
  409.                         /* uhhh, if you ever have to set the property of a proprty, call me */
  410.                         /* and we'll find help */
  411.                         break;
  412.                         
  413.                 }
  414.                 break;
  415.         }
  416.     }
  417.     gCurrentReply = nil;
  418.     return(myErr);
  419. }
  420.  
  421. /* TextFromWindow returns a token identifying a text object attached to a window. */
  422. /* If there is no text in this window, it returns an error */
  423. pascal OSErr TextFromWindow(DescType desiredClass, const AEDesc *container, DescType containerClass, DescType form,
  424.                             const AEDesc *selectionData, AEDesc *value, long LongInt)
  425. {
  426. #pragma unused (desiredClass,form,LongInt)
  427.     OSErr myErr = noErr;
  428.     WindowPtr theWindow;
  429.     windowCHandle tempWC;
  430.     short textNumber;
  431.     CTextObjHandle newText;
  432.     
  433.     mVerboseOutput("\p\nGetting a Text from a Window")
  434.     if (containerClass != cWindow) {
  435.         myErr = errAENoSuchObject;                          /* no such luck speedy */
  436.         AddToReply("\pYou did not ask for a text from a window, it's container", 0);
  437.     } else {
  438.         /* the container contains a window token in it's hot little datahandle */
  439.         theWindow = *((WindowPtr *)(*(container->dataHandle)));
  440.         
  441.         tempWC = (windowCHandle)GetWRefCon(theWindow);
  442.         /* Does this window contain a text edit record???? */
  443.         if ((*tempWC)->boxHandle) {
  444.             /* which number Text did they ask for?  Our sample only allows one */
  445.             /* Text per window, so if it isn't one, bail */
  446.             ShortFromDesc(&textNumber, selectionData);
  447.             if (textNumber == 1) {
  448.                 /* create an cText object and pass it back */
  449.                 newText = (CTextObjHandle)NewHandle(sizeof(CTextObject));
  450.                 HLock((Handle)newText);
  451.                 /* fill it in */
  452.                 (*newText)->theOwningWindow = theWindow;
  453.                 (*newText)->theText = (*tempWC)->boxHandle;
  454.                 myErr = AECreateDesc(cText, (Ptr)*newText, sizeof(CTextObject), value);
  455.                 DisposeHandle((Handle)newText);              /* no longer needed */
  456.             } else {
  457.                 myErr = errAENoSuchObject;
  458.                 AddToReply("\pNo Text Box with that index", 0);
  459.             }
  460.         } else {
  461.             /* no text in this window */
  462.             myErr = errAENoSuchObject;
  463.             AddToReply("\pNo Text Box in the window you specified", 0);
  464.         }
  465.     }
  466.     return(myErr);
  467. }
  468.  
  469. /* Grab a word from the text */
  470. /* This is a 3rd level call from AEResolve.  Before we got to here, AEResolve has  */
  471. /* already called our WindFromNull and TextFromWindow accessors, the container */
  472. /* passed in is our text container token (probably) */
  473. pascal OSErr WordFromText(DescType desiredClass, const AEDesc *container, DescType containerClass, DescType form,
  474.                           const AEDesc *selectionData, AEDesc *value, long LongInt)
  475. {
  476.  #pragma unused (desiredClass,containerClass,form,LongInt)
  477.     OSErr myErr = noErr;
  478.     long wordCount;
  479.     long wordStart;
  480.     long wordEnd;
  481.     short countToGet;
  482.     SignedByte textHState;
  483.     CWordObjHandle wordToken;
  484.     Handle theText;
  485.     /* Since we'e getting word from text, we know the container is our Text token */
  486.     CTextObjHandle ourTextObject = (CTextObjHandle)(container->dataHandle);
  487.     /* grab the text for later */
  488.     theText = (Handle)TEGetText((*ourTextObject)->theText);
  489.     textHState = HGetState(theText);
  490.     HLock(theText);
  491.     if (GetHandleSize(theText)) {
  492.         mVerboseOutput("\p\nGetting a word from a Text")
  493.         ShortFromDesc(&countToGet, selectionData);
  494.         
  495.         /* call my word counter with a stopAt of the selection data */
  496.         CountWords(container, &wordCount, countToGet, &wordStart);
  497.         /* CountWords returns negative if there weren't any, or if we went too far */
  498.         if (wordCount > 0) {
  499.             /* now count to the next word, so we know the range */
  500.             /* I know, I know, this is horribly inefficient, but it's an example, OK? */
  501.             CountWords(container, &wordCount, countToGet + 1, &wordEnd);
  502.             if (wordCount < 0) {
  503.                 /* ooops, no more words.  Just go to text len then */
  504.                 wordEnd = GetHandleSize(theText);
  505.             }
  506.             /* return a word token */
  507.             wordToken = (CWordObjHandle)NewHandleClear(sizeof(CWordObject));
  508.             /* fill in the token */
  509.             (*wordToken)->theOwningWindow = (*ourTextObject)->theOwningWindow;
  510.             (*wordToken)->theText = (*ourTextObject)->theText;
  511.             (*wordToken)->startPos = wordStart;
  512.             (*wordToken)->endPos = wordEnd;
  513.             /* create the token */
  514.             myErr = AECreateDesc(cWord, (Ptr)*wordToken, sizeof(CWordObject), value);
  515.         } else {
  516.             /* error, no words */
  517.             myErr = errAENoSuchObject;
  518.             AddToReply("\pCould not find this number word in this text", 0);
  519.         }
  520.     } else {
  521.         myErr = errAENoSuchObject;
  522.         AddToReply("\pNo words in this Text", 0);
  523.     }
  524.     HSetState(theText, textHState);
  525.     return(myErr);
  526. }
  527.  
  528. pascal OSErr DrawFromWindow(DescType desiredClass, const AEDesc *container, DescType containerClass, DescType form,
  529.                             const AEDesc *selectionData, AEDesc *value, long LongInt)
  530. {
  531. #pragma unused (desiredClass,containerClass,form,selectionData,LongInt)
  532.     OSErr myErr = noErr;
  533.     mVerboseOutput("\p\nGetting a Drawing Area from a window")
  534.     /* the drawing area token is the same as a window token (i.e. a window pointer) since it gives */
  535.     /* us everything we need to know */
  536.     /* so basically we duplicate the descriptor passed in to us, then change the descType */
  537.     myErr = AEDuplicateDesc(container, value);
  538.     value->descriptorType = cDrawingArea;
  539.     return(myErr);
  540. }
  541.  
  542. /* ShapeFromDraw pulls _any_ kind of shape from my drawing area.  It's called for */
  543. /* a generic cGraphicShape, a cGraphicLine,cRectangle, and cOval.  This is where */
  544. /* your code gets optimized and shrunken, so it is not the nightmare you  */
  545. /* at first thought.  Really */
  546. /* Note that this also gets called for shapes from cWindow (if someone asks that way) */
  547. /* so golly, it's just so useful */
  548. pascal OSErr ShapeFromDraw(DescType desiredClass, const AEDesc *container, DescType containerClass, DescType form,
  549.                            const AEDesc *selectionData, AEDesc *value, long LongInt)
  550. {
  551.  #pragma unused (LongInt)
  552.     OSErr myErr = noErr;
  553.     windowCHandle tempWC;
  554.     long selNumber;
  555.     long tempCounter;
  556.     CShapeObjHandle theToken = (CShapeObjHandle)NewHandleClear(sizeof(CShapeObject));
  557.     ShapesHandle theShapes;
  558.     short numShapes;
  559.     mVerboseOutput("\p\nGetting a Shape from a window, specifically a ")
  560.     AddToAEWindow((Ptr)&desiredClass, kFour);
  561.     /* the container may be either a cWindow or a cDrawingArea.  In our infinite wisdom, */
  562.     /* we have made these tokens the same, so we can use the same routine for both. */
  563.     if (containerClass == cWindow || containerClass == cDrawingArea) {
  564.         /* get the right window struct and the shapes attached to it */
  565.         tempWC = (windowCHandle)GetWRefCon(*((WindowPtr *)(*(container->dataHandle))));
  566.         theShapes = (*tempWC)->theShapes;
  567.         numShapes = (*tempWC)->numShapes;
  568.         /* do some default filling of the shape token, since there's some things */
  569.         /* we already know */
  570.         (*theToken)->theOwningWindow = *((WindowPtr *)(*(container->dataHandle)));
  571.         (*theToken)->type = typeNull;                          /* flag for later folks */
  572.         if (numShapes) {
  573.             /* case off the type of shape we're asking for for the specific one */
  574.             switch (desiredClass) {
  575.                 case cGraphicShape:
  576.                     /* just any old thing */
  577.                     /* case off the form wanted.  Since I am only sending myself graphics */
  578.                     /* by index, that's the case I'll do first */
  579.                 case cGraphicLine:
  580.                 case cRectangle:
  581.                 case cOval:
  582.                     /* and all these shapes are basically the same, so I'll use the same routine */
  583.                     /* in fact, I'm going to go back to my window routine and make the type filed in my Shapes */
  584.                     /* handle a desc type, hold on a minute....  OK, I'm back, this will make it even easier */
  585.                     switch (form) {
  586.                         case formAbsolutePosition:
  587.                             if (selectionData->descriptorType == typeLongInteger) {
  588.                                 
  589.                                 selNumber = *((long *)*(selectionData->dataHandle));
  590.                             } else {
  591.                                 /* see if you can coerce it to a long */
  592.                             }
  593.                             /* find the selNumber-th line in this drawing area */
  594.                             if (selNumber == 0)
  595.                                 selNumber = 1;              /* no 0th */
  596.                             tempCounter = 0;
  597.                             while (theShapes) {
  598.                                 /* 'if' here depending on generic shape or specific type */
  599.                                 if (desiredClass == cGraphicShape) {
  600.                                     tempCounter++;          /* doesn't matter what kind, we care about it */
  601.                                 } else {
  602.                                     if ((*theShapes)->aeType == desiredClass)
  603.                                         tempCounter++;
  604.                                 }
  605.                                 if (tempCounter == selNumber) {
  606.                                     break;
  607.                                 } else {
  608.                                     theShapes = (*theShapes)->nextShape;
  609.                                 }
  610.                             }
  611.                             /* if theShapes is not nil, then we found a shape that suites */
  612.                             
  613.                             if (theShapes) {
  614.                                 /* fill in my token */
  615.                                 (*theToken)->theShape = theShapes;
  616.                                 (*theToken)->shapeNumber = tempCounter;     /* why do I want this?  I dunno */
  617.                                 (*theToken)->type = desiredClass;
  618.                             } else {
  619.                                 myErr = errAENoSuchObject;
  620.                             }
  621.                             break;
  622.                         case formRelativePosition:          /* next, previous */
  623.                             break;
  624.                         case formTest:                      /* A logical or a comparison */
  625.                             break;
  626.                         case formRange:                     /* Two arbitrary objects and everything in between */
  627.                             break;
  628.                         case formPropertyID:                /* Key data is a 4-char property name */
  629.                             break;
  630.                         case formName:                      /* Key data may be of type 'TEXT' */
  631.                             
  632.                             break;
  633.                         default:
  634.                             myErr = errAENoSuchObject;
  635.                             break;
  636.                     }
  637.                     break;
  638.             }
  639.         } else {
  640.             /* no shapes with this window */
  641.             myErr = errAENoSuchObject;
  642.         }
  643.     } else {
  644.         myErr = errAENoSuchObject;
  645.     }
  646.     if (myErr == noErr && (*theToken)->type != typeNull) {
  647.         HLock((Handle)theToken);
  648.         myErr = AECreateDesc((*theToken)->type, (Ptr)*theToken, sizeof(CShapeObject), value);
  649.         DisposeHandle((Handle)theToken);
  650.     }
  651.     return(myErr);
  652. }
  653.  
  654. /* In this example, this will be the first accessor called by any call to AEResolve. */
  655. /* Since we have no other objects sprouting from null but windows, anyone who */
  656. /* wants to know about our documents has to have a cWindow object spec hanging off the */
  657. /* topmost null. */
  658. pascal OSErr WindFromNull(DescType desiredClass, const AEDesc *container, DescType containerClass, DescType form,
  659.                           const AEDesc *selectionData, AEDesc *value, long LongInt)
  660. {
  661.  #pragma unused (desiredClass,container,LongInt)
  662.     WindowPtr returnedWindow = nil;
  663.     WindowPtr tempWindow = nil;
  664.     short index = 0;
  665.     short counter = 0;
  666.     OSErr myErr = noErr;
  667.     Str63 tempMatch;
  668.     Str63 windowName;
  669.     
  670.     mVerboseOutput("\p\nGetting a Window from Nul")
  671.     /* first check to see if we can deal with this, are they asking for a window from Nul?  */
  672.     /* If they're not then we can't handle it */
  673.     if (containerClass != typeNull)
  674.         return(errAENoSuchObject);                          /* not something we recognize */
  675.     /* case off form to see how we'll get the window thing */
  676.     /* all of these may not be supported, but as time goes by they will be */
  677.     
  678.     switch (form) {
  679.         case formAbsolutePosition:                          /* e.g., 1st, -2nd ( 2nd from end) */
  680.             /* ignore the AEStatusWindow in searching this list */
  681.             tempWindow = FrontWindow();
  682.             /* a little utilty routine, see which number window they want */
  683.             ShortFromDesc(&index, (AppleEvent *)selectionData);
  684.             if (index == 0)
  685.                 index = 1;
  686.             if (index == 1 && (((WindowPeek)FrontWindow())->windowKind != kAEStatusWindow)) {
  687.                 /* just grab the front window and return */
  688.                 returnedWindow = FrontWindow();
  689.             } else {
  690.                 /* walk the list  */
  691.                 tempWindow = (WindowPtr)LMGetWindowList();
  692.                 while (tempWindow) {
  693.                     windowCHandle tempWC = (windowCHandle)GetWRefCon(tempWindow);
  694.                     if (index == (*tempWC)->windowIndex) {
  695.                         returnedWindow = tempWindow;
  696.                         break;
  697.                     }
  698.                     tempWindow = (WindowPtr)((WindowPeek)tempWindow)->nextWindow;
  699.                 }
  700.             }
  701.             if (returnedWindow) {
  702.                 
  703.                 myErr = AECreateDesc(cWindow, (Ptr)&returnedWindow, sizeof(returnedWindow), value);
  704.                 mAEErrorDisplay("\p creating object token", myErr);
  705.             } else {
  706.                 /* error, couldn't find the thing */
  707.                 myErr = errAENoSuchObject;
  708.                 AddToReply("\pNo window of that index number", 0);
  709.             }
  710.             break;
  711.         case formRelativePosition:                          /* next, previous */
  712.             break;
  713.         case formTest:                                      /* A logical or a comparison */
  714.             break;
  715.         case formRange:                                     /* Two arbitrary objects and everything in between */
  716.             break;
  717.         case formPropertyID:                                /* Key data is a 4-char property name */
  718.             
  719.             break;
  720.         case formName:                                      /* Key data may be of type 'TEXT' */
  721.             /* gettting one of these here things by name */
  722.             /* so the AEDesc has a text thing in it.  Not a PString, just a charater thing, */
  723.             /* so I'll make it a PString */
  724.             PStringFromTextDesc(&tempMatch, selectionData);
  725.             /* and as usual, walk the window list */
  726.             tempWindow = FrontWindow();
  727.             while (tempWindow) {
  728.                 GetWTitle(tempWindow, windowName);
  729.                 if (EqualString(windowName, tempMatch, false, false))
  730.                     break;
  731.                 tempWindow = (WindowPtr)((WindowPeek)tempWindow)->nextWindow;
  732.             }
  733.             if (tempWindow) {
  734.                 /* we have a match */
  735.                 myErr = AECreateDesc(cWindow, (Ptr)&tempWindow, sizeof(tempWindow), value);
  736.                 mAEErrorDisplay("\p creating object token", myErr);
  737.             } else {
  738.                 /* no match, return an error  */
  739.                 myErr = errAENoSuchObject;
  740.                 AddToReply("\pNo window with that name", 0);
  741.             }
  742.             break;
  743.             
  744.     }
  745.     return(myErr);
  746. }
  747.  
  748. /* PropertyFromWindow gets all the properties of my window object. */
  749. pascal OSErr PropertyFromWindow(DescType desiredClass, const AEDesc *container, DescType containerClass, DescType form,
  750.                                 const AEDesc *selectionData, AEDesc *value, long LongInt)
  751. {
  752.  #pragma unused (desiredClass,containerClass,form,LongInt)
  753.  
  754.     OSErr myErr = noErr;
  755.     Str63 windowName;
  756.     WindowPtr tempPort;
  757.     PropertyTHdl propertyTokenH = (PropertyTHdl)NewHandleClear(sizeof(PropertyToken));
  758.     /* pull a property from the window */
  759.     DescType propertyType = *(DescType *)(*(selectionData->dataHandle));
  760.     ProcessSerialNumber tempPSN;
  761.     Boolean tempBool;
  762.     Handle theData;
  763.     WindowPtr owningWindow;
  764.     windowCHandle owningControl;
  765.     mVerboseOutput("\p\n Getting a window property ")
  766.     AddToAEWindow((Ptr)&propertyType, kFour);
  767.     /* I can fill in some of the token information right now, since I have the window */
  768.     owningWindow = *((WindowPtr *)(*(container->dataHandle)));
  769.     owningControl = (windowCHandle)GetWRefCon(owningWindow);
  770.     (*propertyTokenH)->owningTokenType = cWindow;           /* what this is a property of */
  771.     (*propertyTokenH)->token.window = owningWindow;
  772.     (*propertyTokenH)->inWindow = owningWindow;    /* for consistency, though it's redundant */
  773.     switch (propertyType) {
  774.         /* can't get all of them yet, as this sample grows the amount of properties will also */
  775.         /* grow */
  776.         
  777.         /* What's the name of this window? */
  778.         case pName:
  779.             (*propertyTokenH)->theProperty = pName;
  780.             (*propertyTokenH)->theDataType = typeChar;
  781.             GetWTitle(owningWindow, windowName);
  782.             theData = NewHandle(windowName[0]);
  783.             HLock(theData);
  784.             BlockMove((Ptr)&windowName[1], (Ptr)*theData, windowName[0]);
  785.             HUnlock(theData);
  786.             (*propertyTokenH)->theData = theData;
  787.             break;
  788.             /* Boundry rectangle, in global coordinates */
  789.         case pBounds:
  790.             (*propertyTokenH)->theProperty = pBounds;
  791.             (*propertyTokenH)->theDataType = typeQDRectangle;
  792.             theData = NewHandle(sizeof(Rect));
  793.             HLock(theData);
  794.             BlockMove((Ptr)&owningWindow->portRect, (Ptr)*theData, sizeof(Rect));
  795.             /* now we have to globalize the coordiantes */
  796.             GetPort(&tempPort);
  797.             SetPort(owningWindow);
  798.             SetPort(tempPort);
  799.             /* Now, can we force the MPW C compiler to beleive us that what we're passing is  */
  800.             /* a Point pointer???? */
  801.             LocalToGlobal((Point *)*theData);
  802.             LocalToGlobal((Point *)(*theData + sizeof(Point)));
  803.             /* yes we can, amazing */
  804.             
  805.             HUnlock(theData);
  806.             (*propertyTokenH)->theData = theData;
  807.             
  808.             break;
  809.             /* Do we have a title bar? */
  810.         case pHasTitleBar:
  811.             (*propertyTokenH)->theProperty = pHasTitleBar;
  812.             (*propertyTokenH)->theDataType = typeBoolean;
  813.             theData = NewHandle(sizeof(short));
  814.             **theData = kMyTrue;                            /* they all do */
  815.             (*propertyTokenH)->theData = theData;
  816.             break;
  817.             /* are we a modal window? */
  818.         case pIsModal:
  819.             (*propertyTokenH)->theProperty = pIsModal;
  820.             (*propertyTokenH)->theDataType = typeBoolean;
  821.             theData = NewHandle(sizeof(short));
  822.             **theData = ((WindowPeek)owningWindow)->windowKind & dialogKind;
  823.             (*propertyTokenH)->theData = theData;
  824.             break;
  825.             /* is this window 'dirty'? */
  826.         case pIsModified:
  827.             (*propertyTokenH)->theProperty = pIsModified;
  828.             (*propertyTokenH)->theDataType = typeBoolean;
  829.             theData = NewHandle(sizeof(short));
  830.             **theData = (*owningControl)->windowDirty;
  831.             (*propertyTokenH)->theData = theData;
  832.             break;
  833.             /* can the size be changed? */
  834.         case pIsResizable:
  835.             (*propertyTokenH)->theProperty = pIsResizable;
  836.             (*propertyTokenH)->theDataType = typeBoolean;
  837.             theData = NewHandle(sizeof(short));
  838.             **theData = kMyTrue;
  839.             (*propertyTokenH)->theData = theData;
  840.             break;
  841.             /* stationary? */
  842.         case pIsStationeryPad:
  843.             (*propertyTokenH)->theProperty = pIsResizable;
  844.             (*propertyTokenH)->theDataType = typeBoolean;
  845.             theData = NewHandle(sizeof(short));
  846.             **theData = false;
  847.             (*propertyTokenH)->theData = theData;
  848.             break;
  849.             /* Are we in the users face right now? */
  850.         case pIsFrontProcess:
  851.             (*propertyTokenH)->theProperty = pIsResizable;
  852.             (*propertyTokenH)->theDataType = typeBoolean;
  853.             theData = NewHandle(sizeof(short));
  854.             GetFrontProcess(&tempPSN);
  855.             SameProcess(&tempPSN, &gOurSN, &tempBool);
  856.             **theData = tempBool;
  857.             (*propertyTokenH)->theData = theData;
  858.             break;
  859.             /* are we in the Zoomed state? */
  860.         case pIsZoomed:
  861.             break;
  862.             /* are we visible to the user now? */
  863.         case pVisible:
  864.             (*propertyTokenH)->theProperty = pVisible;
  865.             (*propertyTokenH)->theDataType = typeBoolean;
  866.             theData = NewHandle(sizeof(short));
  867.             **theData = kMyTrue;                            /* I'm only returning visible windows  */
  868.             (*propertyTokenH)->theData = theData;
  869.             break;
  870.             /* What's our class? */
  871.         case pClass:
  872.             (*propertyTokenH)->theProperty = pClass;
  873.             (*propertyTokenH)->theDataType = typeType;
  874.             
  875.             theData = NewHandle(sizeof(DescType));
  876.             HLock(theData);
  877.             *((DescType *)*theData)=cWindow;
  878.             HUnlock(theData);
  879.             (*propertyTokenH)->theData = theData;
  880.             
  881.             break;
  882.             
  883.     }
  884.     
  885.     /* and return the token */
  886.     if (!myErr) {
  887.         HLock((Handle)propertyTokenH);
  888.         myErr = AECreateDesc(typeProperty, (Ptr)*propertyTokenH, sizeof(PropertyToken), value);
  889.         /* dispose of the token handle, but NOT the data handle I added, since the AEM */
  890.         /* had no idea that I put a handle inside the data, so it didn't copy that */
  891.         /* Later, when the token itself is disposed that handle will be  */
  892.         /* freed up. */
  893.         DisposeHandle((Handle)propertyTokenH);
  894.         mAEErrorDisplay("\p creating property token", myErr);
  895.         
  896.     }
  897.     return(myErr);
  898. }
  899. /* This allows someone to get properties from my text */
  900. pascal OSErr PropertyFromText(DescType desiredClass, const AEDesc *container, DescType containerClass, DescType form,
  901.                               const AEDesc *selectionData, AEDesc *value, long LongInt)
  902. {
  903. #pragma unused (desiredClass,containerClass,form,value,LongInt)
  904.  
  905.     OSErr myErr = noErr;
  906.     PropertyTHdl propertyTokenH = (PropertyTHdl)NewHandleClear(sizeof(PropertyToken));
  907.     CTextObjHandle myTextHandle;                            /* I include a text object token in my text property token */
  908.     /* kinda circular, but hey... */
  909.     /* pull a property from a text */
  910.     
  911.     DescType propertyType = *(DescType *)(*(selectionData->dataHandle));
  912.     Handle theData;
  913.     RGBColor myBlack =  {
  914.         0, 0, 0
  915.     };                                                      /* for the Color question */
  916.     Str255 tempString;
  917.     windowCHandle owningControl;
  918.     mVerboseOutput("\p\n Getting a text property ")
  919.     AddToAEWindow((Ptr)&propertyType, kFour);
  920.     /* I can fill in some of the token information right now, since I have the window */
  921.     myTextHandle = (CTextObjHandle)container->dataHandle;
  922.     owningControl = (windowCHandle)GetWRefCon((*myTextHandle)->theOwningWindow);
  923.     (*propertyTokenH)->owningTokenType = cText;             /* what this is a property of */
  924.     (*propertyTokenH)->token.textHandle = (*myTextHandle)->theText;
  925.     (*propertyTokenH)->theProperty = propertyType;
  926.     (*propertyTokenH)->inWindow = (*myTextHandle)->theOwningWindow;
  927.     switch (propertyType) {WritingCodePtr theCode;
  928.         
  929.         case pAnyCharTextStyles:
  930.             (*propertyTokenH)->theDataType = typeBoolean;
  931.             theData = NewHandle(sizeof(short));
  932.             **theData = false;                              /* we have no style */
  933.             (*propertyTokenH)->theData = theData;
  934.             break;
  935.         case pClass:
  936.             (*propertyTokenH)->theDataType = typeType;
  937.             theData = NewHandle(sizeof(DescType));
  938.             **theData = cText;                              /* they all do */
  939.             (*propertyTokenH)->theData = theData;
  940.             break;
  941.         case pColor:
  942.             (*propertyTokenH)->theDataType = typeRGBColor;
  943.             /* always black in this example */
  944.             theData = NewHandle(sizeof(RGBColor));
  945.             HLock(theData);
  946.             BlockMove((Ptr)&myBlack, (Ptr)*theData, sizeof(RGBColor));
  947.             HUnlock(theData);
  948.             (*propertyTokenH)->theData = theData;
  949.             break;
  950.         case pFont:
  951.             /* get the ID, translate to a name, and return as text */
  952.             /* our token contains a TERecord, which contains the font ID */
  953.             GetFontName((*(*propertyTokenH)->token.textHandle)->txFont, &tempString);
  954.             theData = NewHandle(tempString[0]);
  955.             HLock(theData);
  956.             BlockMove((Ptr)&tempString[1], (Ptr)*theData, tempString[0]);
  957.             HUnlock(theData);
  958.             (*propertyTokenH)->theData = theData;
  959.             
  960.             break;
  961.         case pPointSize:
  962.             /* Object Class ID: cFixed16 */
  963.             (*propertyTokenH)->theDataType = typeFixed;
  964.             theData = NewHandleClear(sizeof(long));
  965.             *((short *)*theData) = (*(*propertyTokenH)->token.textHandle)->txSize;        
  966.             (*propertyTokenH)->theData = theData;
  967.             
  968.         case pScriptTag:
  969.             (*propertyTokenH)->theDataType = typeIntlWritingCode;
  970.             theData = NewHandle(sizeof(WritingCode));
  971.             theCode = (WritingCodePtr) *theData;
  972.             HLock(theData);
  973.             theCode->theScriptCode = FontScript();
  974.             theCode->theLangCode = iuSystemCurLang;
  975.             HUnlock(theData);
  976.             (*propertyTokenH)->theData = theData;
  977.  
  978.             break;
  979.         case pTextStyles:
  980.             /* in my sample, no style */
  981.             (*propertyTokenH)->theDataType = typeBoolean;
  982.             theData = NewHandle(sizeof(short));
  983.             **theData = false;                              /* we have no style */
  984.             (*propertyTokenH)->theData = theData;
  985.             
  986.             break;
  987.             /*****************************/
  988.             
  989.     }                                                       /* endswitch */
  990.     
  991.     
  992.     return(myErr);
  993. }
  994.  
  995. pascal OSErr PropertyFromShape(DescType desiredClass, const AEDesc *container, DescType containerClass, DescType form,
  996.                                const AEDesc *selectionData, AEDesc *value, long LongInt)
  997. {
  998. #pragma unused (desiredClass,containerClass,form,LongInt)
  999.     OSErr myErr = noErr;
  1000.     PropertyTHdl propertyTokenH = (PropertyTHdl)NewHandleClear(sizeof(PropertyToken));
  1001.     /* pull a property from the window */
  1002.     CShapeObjHandle theShapeToken;                          /* the token for this shape */
  1003.     RGBColor white =  {
  1004.         0xFFFF, 0xFFFF, 0xFFFF
  1005.     };
  1006.     ShapesHandle theShape;
  1007.     short penSize = 1;
  1008.     long myCopy = 0;
  1009.     DescType propertyType = *(DescType *)(*(selectionData->dataHandle));
  1010.     Handle theData;
  1011.     windowCHandle owningControl;
  1012.     DescType shapeType;
  1013.     mVerboseOutput("\p\n Getting a property from a shape")
  1014.     theShapeToken = (CShapeObjHandle)container->dataHandle;
  1015.     owningControl = (windowCHandle)GetWRefCon((*theShapeToken)->theOwningWindow);
  1016.     shapeType = (*theShapeToken)->type;
  1017.     theShape = (*theShapeToken)->theShape;
  1018.     (*propertyTokenH)->owningTokenType = shapeType;
  1019.     (*propertyTokenH)->token.shapeHandle = (*theShapeToken)->theShape;
  1020.     (*propertyTokenH)->theProperty = propertyType;
  1021.     (*propertyTokenH)->inWindow = (*theShapeToken)->theOwningWindow;
  1022.     /* so after filling in a bunch, all we need now is the data type and the data itself */
  1023.     switch (propertyType) {
  1024.         case pBounds:
  1025.         case pDefinitionRect:
  1026.             /* This is the same as the bounds rect in my example */
  1027.             
  1028.             /* return a bounds rect, pretty easy */
  1029.             (*propertyTokenH)->theDataType = typeQDRectangle;
  1030.             theData = NewHandle(sizeof(Rect));
  1031.             HLock(theData);
  1032.             BlockMove((Ptr)&(*theShape)->theRect, (Ptr)*theData, sizeof(Rect));
  1033.             /* this of course stays in local coordinates for the owning port */
  1034.             (*propertyTokenH)->theData;
  1035.             break;
  1036.         case pClass:
  1037.             (*propertyTokenH)->theDataType = typeType;
  1038.             theData = NewHandle(sizeof(DescType));
  1039.             HLock(theData);
  1040.             /* I know, blockmoving 4 bytes is silly.  */
  1041.             BlockMove((Ptr)&shapeType, (Ptr)*theData, sizeof(DescType));
  1042.             break;
  1043.         case pFillColor:
  1044.             (*propertyTokenH)->theDataType = typeRGBColor;
  1045.             /* always white in this example */
  1046.             theData = NewHandle(sizeof(RGBColor));
  1047.             HLock(theData);
  1048.             BlockMove((Ptr)&white, (Ptr)*theData, sizeof(RGBColor));
  1049.             HUnlock(theData);
  1050.             (*propertyTokenH)->theData = theData;
  1051.             
  1052.             break;
  1053.         case pFillPattern:
  1054.         case pPenPattern:
  1055.             break;
  1056.         case pPenColor:
  1057.             (*propertyTokenH)->theDataType = typeRGBColor;
  1058.             theData = NewHandle(sizeof(RGBColor));
  1059.             HLock(theData);
  1060.             BlockMove((Ptr)&(*theShape)->theColor, (Ptr)*theData, sizeof(RGBColor));
  1061.             HUnlock(theData);
  1062.             (*propertyTokenH)->theData = theData;
  1063.             
  1064.             break;
  1065.             
  1066.         case pPenWidth:
  1067.             (*propertyTokenH)->theDataType = typeShortInteger;
  1068.             /* always white in this example */
  1069.             theData = NewHandle(sizeof(short));
  1070.             HLock(theData);
  1071.             BlockMove((Ptr)&penSize, (Ptr)*theData, sizeof(short));
  1072.             break;
  1073.         case pTransferMode:
  1074.             (*propertyTokenH)->theDataType = typeEnumeration;
  1075.             /* always white in this example */
  1076.             theData = NewHandle(sizeof(long));
  1077.             HLock(theData);
  1078.             BlockMove((Ptr)&myCopy, (Ptr)*theData, sizeof(long));
  1079.             break;
  1080.     }
  1081.     HUnlock(theData);
  1082.     /* dangme I forgot to move what I just did into result..... */
  1083.     if (!myErr) {
  1084.         HLock((Handle)propertyTokenH);
  1085.         myErr = AECreateDesc(typeProperty, (Ptr)*propertyTokenH, sizeof(PropertyToken), value);
  1086.         /* dispose of the token handle, but NOT the data handle I added, since the AEM */
  1087.         /* had no idea that I put a handle inside the data, so it didn't copy that */
  1088.         /* Later, when the token itself is disposed that handle will be  */
  1089.         /* freed up. */
  1090.         DisposeHandle((Handle)propertyTokenH);
  1091.         mAEErrorDisplay("\p creating property token", myErr);
  1092.         
  1093.     }
  1094.     
  1095.     return(myErr);
  1096. }
  1097.  
  1098.  
  1099. /* You may never need a dispose function.  If all you use for tokens are */
  1100. /* simple AEDescs, the OSL will do all the disposal for you. */
  1101. /* In my case, my tokens contain  handles, so I have to  */
  1102. /* do some disposal myself. */
  1103. pascal OSErr MyDisposeTokenProc(AEDesc *unneededToken)
  1104. {
  1105.     OSErr myErr = noErr;
  1106.     PropertyTHdl myProp;
  1107.     mVerboseOutput("\p\nDisposing a Token: ")
  1108.     AddToAEWindow((Ptr)&(unneededToken->descriptorType), kFour);
  1109.     /* most of the time I'll be doing a simple AEDisposeDesc.  The only time I need  */
  1110.     /* something more complex is when I'm disposing of a property descriptor, since */
  1111.     /* I have a handle inside that */
  1112.     switch (unneededToken->descriptorType) {
  1113.         /* these two are simple */
  1114.         case cWindow:
  1115.         case cText:
  1116.             myErr = AEDisposeDesc(unneededToken);
  1117.             break;
  1118.             /* these two have imbedded handles */
  1119.         case cWord:
  1120.             myErr = AEDisposeDesc(unneededToken);
  1121.             break;
  1122.         case typeProperty:
  1123.             myProp = (PropertyTHdl)unneededToken->dataHandle;
  1124.             DisposeHandle((*myProp)->theData);
  1125.             myErr = AEDisposeDesc(unneededToken);
  1126.             
  1127.             break;
  1128.             
  1129.         default:
  1130.             /* I default to just disposing of the token, ne ces pa  */
  1131.             AEDisposeDesc(unneededToken);
  1132.             break;
  1133.     }
  1134.     return(myErr);
  1135. }
  1136.  
  1137. /* not yet implemented (and also not installed as a callback) */
  1138. pascal OSErr MyCompareProc(DescType oper, const AEDesc *obj1, const AEDesc *obj2, Boolean *result)
  1139. {
  1140. #pragma unused (oper,obj1,obj2,result)
  1141.     OSErr myErr = noErr;
  1142.     mVerboseOutput("\p\nComparing Objects")
  1143.     return(myErr);
  1144. }
  1145.  
  1146. pascal OSErr MyCountProc(DescType desiredType, DescType containerClass, const AEDesc *container, long *result)
  1147. {
  1148.     OSErr myErr = noErr;
  1149.     long counter = 0;
  1150.     WindowPtr windows;
  1151.     windowCHandle tempWC;
  1152.     switch (desiredType) {
  1153.         case cWindow:
  1154.             /* should be conting windows from nul */
  1155.             mVerboseOutput("\p\nCounting Windows")
  1156.             windows = (WindowPtr)LMGetWindowList();
  1157.             while (windows) {
  1158.                 counter++;
  1159.                 windows = (WindowPtr)((WindowPeek)windows)->nextWindow;
  1160.             }
  1161.             *result = counter;
  1162.             break;
  1163.         case kAEMyShape:
  1164.             mVerboseOutput("\p\nCounting Shapes")
  1165.             /* getting this from a specific container, i.e. a winder. */
  1166.             switch (containerClass) {
  1167.                 case cWindow:
  1168.                 case cDrawingArea:
  1169.                     /* we're OK so far */
  1170.                     /* get my window pointer from the container passed */
  1171.                     CountShapes(container,&counter,nil,nil,&desiredType);
  1172.                     *result = counter;
  1173.                     break;
  1174.                 case typeNull:
  1175.                     /* this would mean all the possible shapes  */
  1176.                     break;
  1177.             }
  1178.             break;
  1179.         case cText:
  1180.             mVerboseOutput("\p\nCounting Texts")
  1181.             switch (containerClass) {
  1182.                 /* I can count texts in a window and in Null (the app) */
  1183.                 case typeNull:
  1184.                     /* walk all my document windows and see how many texts exisit */
  1185.                     windows = FrontWindow();
  1186.                     /* there may not be any, o'course */
  1187.                     while (windows) {
  1188.                         tempWC = (windowCHandle)GetWRefCon(windows);
  1189.                         if ((*tempWC)->boxHandle)
  1190.                             counter++;
  1191.                         windows = (WindowPtr)((WindowPeek)windows)->nextWindow;
  1192.                     }
  1193.                     *result = counter;
  1194.                     break;
  1195.                 case cWindow:
  1196.                     /* so we know the container desc is my window token */
  1197.                     windows = (WindowPtr)*(container->dataHandle);
  1198.                     tempWC = (windowCHandle)GetWRefCon(windows);
  1199.                     /* there is either one or none */
  1200.                     *result = (((*tempWC)->boxHandle) ? 1 : 0);
  1201.                     break;
  1202.                 default:
  1203.                     mVerboseOutput("\p\nAsked for text count from something we don't understand ")
  1204.                     myErr = errAECantHandleClass;
  1205.                             /* add new Winter '92 registry error code <ckh 1.0.2>*/
  1206.                     AddToReply("\p Cant count this class",errAECantHandleClass);
  1207.  
  1208.                     counter = 0;
  1209.                     break;
  1210.             }
  1211.             *result = counter;
  1212.             break;
  1213.         case cWord:
  1214.             /* Since I have to count words in another place (when I get the word) */
  1215.             /* I will call my subroutine, saying I don't want to stop */
  1216.             mVerboseOutput("\p\nCounting Words ")
  1217.             CountWords(container, &counter, nil, nil);
  1218.             *result = counter;
  1219.             break;
  1220.         case cGraphicLine:
  1221.         case cRectangle:
  1222.         case cOval:
  1223.         case cGraphicShape:
  1224.             /* all these are basically the same */
  1225.             CountShapes(container, &counter, nil, nil, &desiredType);
  1226.             *result = counter;
  1227.             break;
  1228.         default:
  1229.             myErr = errAENoSuchObject;                      /* I don't know what's being asked for */
  1230.             break;
  1231.  
  1232.     }
  1233.     return(myErr);
  1234. }
  1235.  
  1236. void CountWords(const AEDesc *container, long *theCount, long stopAt, long *position)
  1237. {
  1238.     CTextObjHandle ourTextObject;
  1239.     Handle theText;
  1240.     SignedByte textState;
  1241.     char *textPtr;
  1242.     register char letter;
  1243.     long wordCount = 1;                                     /* I'm getting passed a 1 based count to find */
  1244.     Boolean inSpaces = false;
  1245.     register long positionNow = 0;
  1246.     long lastLetter = 0;
  1247.     /* So we have a text object here, which contains a TEHandle */
  1248.     /* We step through the handle counting words */
  1249.     /* get the text from my cText token */
  1250.     
  1251.     AddAENum(stopAt);
  1252.     ourTextObject = (CTextObjHandle)(container->dataHandle);
  1253.     *position = -1;
  1254.     theText = (Handle)TEGetText((*ourTextObject)->theText);
  1255.     textState = HGetState(theText);
  1256.     HLock(theText);                                         /* AddAENum makes some TextEdit calls, so I need to lock this */
  1257.     /* how many characters are in it? */
  1258.     lastLetter = GetHandleSize(theText);
  1259.     if (lastLetter) {
  1260.         /* now this is a slow and agonizing word count routine, it's not intended to be any more than that */
  1261.         textPtr = (char *)*theText;
  1262.         for (positionNow = 0; positionNow < lastLetter; positionNow++) {
  1263.             letter = *(textPtr + positionNow);
  1264.             if (letter == kSpace) {
  1265.                 if (!inSpaces)
  1266.                     wordCount++;
  1267.                 inSpaces = kMyTrue;
  1268.                 if (stopAt && stopAt == wordCount) {
  1269.                     if (position)
  1270.                         *position = positionNow;
  1271.                     break;
  1272.                 }
  1273.             } else {
  1274.                 inSpaces = false;
  1275.             }
  1276.         }
  1277.         /* Did we have fun counting words?  Yes? */
  1278.         /* OK, we have a word count */
  1279.         /* if position is still negative, we didn't get to this word.  Maybe there weren't enough */
  1280.         if (*position >= 0)
  1281.             *theCount = wordCount;
  1282.         else
  1283.             *theCount = -1;
  1284.         AddAENum(wordCount);
  1285.     } else {
  1286.         /* no words (or letters) in this thing */
  1287.         *theCount = -1;
  1288.     }
  1289.     HSetState(theText, textState);
  1290. }
  1291.  
  1292. void CountShapes(const AEDesc *container, long *theCount, long stopAt, long *position, DescType *whichType)
  1293. {
  1294. #pragma unused (stopAt,position)
  1295.     WindowPtr owner;
  1296.     windowCHandle tempWCH;
  1297.     ShapesHandle  theShapes;
  1298.     mVerboseOutput("\p\nCounting Shapes ")
  1299.     if (container->descriptorType == cWindow || container->descriptorType == cDrawingArea) {
  1300.         owner = *((WindowPtr *)(*(container->dataHandle)));
  1301.         tempWCH = (windowCHandle)GetWRefCon(owner);
  1302.         if(*whichType == cGraphicShape){
  1303.         *theCount = (*tempWCH)->numShapes;
  1304.         } else {
  1305.         /* find specific things */
  1306.         *theCount = 0;
  1307.         theShapes = (*tempWCH)->theShapes;
  1308.         while(theShapes){
  1309.         if((*theShapes)->aeType == *whichType)*theCount +=1;
  1310.         theShapes = (*theShapes)->nextShape;
  1311.         }
  1312.         }
  1313.         
  1314.     } else {
  1315.         /* no luck joe, can't count items from this container */
  1316.         *theCount = -1;
  1317.     }
  1318. }
  1319.  
  1320. /* not yet implemented (and also not installed as a callback) */
  1321. pascal OSErr MyGetMarkTokenProc(const AEDesc *dContainerToken, DescType containerClass, AEDesc *result)
  1322. {
  1323. #pragma unused (dContainerToken,containerClass,result)
  1324.     OSErr myErr = noErr;
  1325.     mVerboseOutput("\p\nGetting a Mark token")
  1326.     return(myErr);
  1327. }
  1328.  
  1329. /* not yet implemented (and also not installed as a callback) */
  1330. pascal OSErr MyMarkProc(const AEDesc *dToken, const AEDesc *markToken, long index)
  1331. {
  1332.     OSErr myErr = noErr;
  1333. #pragma unused (dToken,markToken,index) 
  1334.     mVerboseOutput("\p\nMarking something")
  1335.     return(myErr);
  1336. }
  1337.  
  1338. /* not yet implemented (and also not installed as a callback) */
  1339. pascal OSErr MyAdjustMarksProc(long newStart, long newStop, const AEDesc *markToken)
  1340. {
  1341. #pragma unused (newStart,newStop,markToken)
  1342.     OSErr myErr = noErr;
  1343.     mVerboseOutput("\p\nAdjusting Marks")
  1344.     return(myErr);
  1345. }
  1346.  
  1347. /* This builds our GetData event, based on the things you've set up in the object */
  1348. /* definition dialogs. */
  1349. OSErr BuildGetDataEvent(AppleEvent *thisEvent, short which)
  1350. {
  1351.     OSErr myErr = noErr;
  1352.     AEDesc object;
  1353.     myErr = BuildFullObject(&object, which);
  1354.     myErr = AEPutParamDesc(thisEvent, keyDirectObject, &object);
  1355.     mAEErrorDisplay("\p putting object", myErr)
  1356.     if (!myErr)
  1357.         AEDisposeDesc(&object);
  1358.     /* one last thing to deal with.  We _can_, if we want, add a keyAERequestedType parameter. */
  1359.     /* this is optional, and specifies the format of the data we'd like to work with. */
  1360.     /* NOTE:  The receiver of this event may ignore this completely.  There may be */
  1361.     /* two reasons for the ignoring.... */
  1362.     /* 1) It's an optional param.  That means the receiver may not even look for it, or */
  1363.     /* know it's there. */
  1364.     /* 2) They may not be able to do it.  They may not be able to coerce their data to the */
  1365.     /* type you'd like to get back.  If so, they'll still send data back, it'll just */
  1366.     /* be in the standard format (as described in the registry) for this event and object. */
  1367.     /*  You will have to do the coercion yourself. */
  1368.     /* By The Way:  If you add system level coercion routines for the types you like to see */
  1369.     /* other apps on the same machine will be able to coerce to your types without having any */
  1370.     /* understanding of them. */
  1371.     /* By The Way II:  If you do not get back the type you want, you should also */
  1372.     /* try and coerce it yourself.  Perhaps you have the correct coercion */
  1373.     /* routine on your machine, one that was not available to the other app. */
  1374.     return(myErr);
  1375. }
  1376.  
  1377. /* This builds our SetData event, based on the things you've set up in the object */
  1378. /* definition dialogs. */
  1379. /* It's a little more complicated, since I have to throw in dialogs to get the  */
  1380. /* new value you want */
  1381.  
  1382. OSErr BuildSetDataEvent(AppleEvent *thisEvent, short which)
  1383. {
  1384.     OSErr myErr = noErr;
  1385.     DialogPtr tdial;
  1386.     short strung;
  1387.     RGBColor oldColor = {0,0,0};
  1388.     RGBColor newColor;
  1389.     Str63 paramString;
  1390.     short hitItem = 0;
  1391.     DescType theDataDesc;
  1392.     short doVis;
  1393.     short *tempShortPtr;
  1394.     Handle theDataHandle = NewHandle(0);
  1395.     AEDesc object;
  1396.     AEDesc dataToSet;
  1397.     /* build the window based on previous things (from dialog) */
  1398.     myErr = BuildFullObject(&object, which);
  1399.     mAEErrorDisplay("\p putting object", myErr)
  1400.     if (!myErr) {
  1401.         /* We've got the object built.  Since this is a SetData event, now we have to add the */
  1402.         /* actual data to set to the thing.  Yes kids, its DialogBox time.... */
  1403.         /* There's nothing interesting here except dialog box handling, if you want to get */
  1404.         /* on to Objects and Æs again, skip ahead to ••here•• */
  1405.         tdial = CommonDStart(kSetDDialog, 0, 0);
  1406.         /* show the correct items */
  1407.         switch (which) {
  1408.             case kWindowBoundsItem:
  1409.                 ShowDialogItem(tdial, kRectTextItem);
  1410.                 ShowDialogItem(tdial, kRectEdit1);
  1411.                 ShowDialogItem(tdial, kRectEdit2);
  1412.                 ShowDialogItem(tdial, kRectEdit3);
  1413.                 ShowDialogItem(tdial, kRectEdit4);
  1414.                 break;
  1415.             case kWindowTitleItem:
  1416.                 ShowDialogItem(tdial, kNewTitleWordsItem);
  1417.                 ShowDialogItem(tdial, kNewTitleEditLineItem);
  1418.                 break;
  1419.             case kWindowVisiblityItem:
  1420.                 ShowDialogItem(tdial, kMakeVisItem);
  1421.                 ShowDialogItem(tdial, kMakeInvisItem);
  1422.                 
  1423.                 break;
  1424.             case kAllText:
  1425.                 ShowDialogItem(tdial, kNewTextItem);
  1426.                 ShowDialogItem(tdial, kNewText);
  1427.                 
  1428.                 break;
  1429.             case kWordText:
  1430.                 ShowDialogItem(tdial, kNewWordItem);
  1431.                 ShowDialogItem(tdial, kNewText);
  1432.                 
  1433.                 break;
  1434.             case kShapeItem:
  1435.                 ShowDialogItem(tdial, kNewSBoundsRadio);
  1436.                 ShowDialogItem(tdial, kNewSColorRadio);
  1437.                 ShowDialogItem(tdial, kNewSColorButton);
  1438.                 ShowDialogItem(tdial, kRectEdit1);
  1439.                 ShowDialogItem(tdial, kRectEdit2);
  1440.                 ShowDialogItem(tdial, kRectEdit3);
  1441.                 ShowDialogItem(tdial, kRectEdit4);
  1442.                 HiliteControl(SnatchHandle(tdial, kNewSColorButton),255);
  1443.                 SetControlValue(SnatchHandle(tdial, kNewSBoundsRadio), true);    
  1444.                 break;
  1445.         }
  1446.         if(which != kShapeItem)
  1447.             strung = which - 1 + kSettingVis;
  1448.         else
  1449.             strung = kSettingShape;
  1450.         GetIndString(paramString, kGeneralStrings, strung);
  1451.         /* I'm going to add a little more text here */
  1452.         if(which == kShapeItem)
  1453.             {DescType shapeTypes[] =  {
  1454.                cGraphicLine, cRectangle, cOval
  1455.             };
  1456.             Str32 theNum;
  1457.             HLock((Handle)gShapeObjSpecHandle);
  1458.             theNum[0] = 6;
  1459.             theNum[1] = ' ';
  1460.             BlockMove((Ptr)&(*gShapeObjSpecHandle)->form,(Ptr)&theNum[2],kFour);
  1461.             theNum[6] = ' ';
  1462.             AppendString(¶mString,&theNum);
  1463.             NumToString((*gShapeObjSpecHandle)->u.index,&theNum);
  1464.             AppendString(¶mString,&theNum);
  1465.             HUnlock((Handle)gShapeObjSpecHandle);
  1466.             
  1467.             }
  1468.         ParamText(paramString, "", "", "");
  1469.         ShowWindow(tdial);
  1470.         DrawDialog(tdial);
  1471.         if (which == kWindowVisiblityItem)
  1472.             SetControlValue(SnatchHandle(tdial, kMakeVisItem), true);
  1473.         doVis = true;
  1474.         
  1475.         {
  1476.             ModalFilterUPP upp = NewModalFilterProc(standardDialogFilter);
  1477.             while (hitItem != ok && hitItem != cancel) {
  1478.                 ModalDialog(upp, &hitItem);
  1479.                 /* the only one that has anything we need to set is the visibility one */
  1480.                 if (which == kWindowVisiblityItem) {
  1481.                     if (hitItem == kMakeVisItem || hitItem == kMakeInvisItem) {
  1482.                         SetControlValue(SnatchHandle(tdial, kMakeVisItem), false);
  1483.                         SetControlValue(SnatchHandle(tdial, kMakeInvisItem), false);
  1484.                         SetControlValue(SnatchHandle(tdial, hitItem), true);
  1485.                     }
  1486.                 }
  1487.                 if (which == kShapeItem) {
  1488.                     switch (hitItem){
  1489.                     Point where;
  1490.                     case kNewSBoundsRadio:
  1491.                     case kNewSColorRadio:
  1492.                         SetControlValue(SnatchHandle(tdial, kNewSBoundsRadio), false);
  1493.                         SetControlValue(SnatchHandle(tdial, kNewSColorRadio), false);
  1494.                         SetControlValue(SnatchHandle(tdial, hitItem), true);
  1495.                     if(GetControlValue(SnatchHandle(tdial, kNewSColorRadio)))
  1496.                     HiliteControl(SnatchHandle(tdial, kNewSColorButton),0);
  1497.                     else
  1498.                     HiliteControl(SnatchHandle(tdial, kNewSColorButton),255);
  1499.                     break;
  1500.                     case kNewSColorButton:
  1501.                 GetIndString(paramString, kGeneralStrings, kNewSCol);
  1502.                 where.v = -1;
  1503.                 where.h = -1;
  1504.                     GetColor(where,paramString,&oldColor,&newColor);
  1505.                     break;
  1506.                     }
  1507.                 }
  1508.             }
  1509.             DisposeRoutineDescriptor(upp);
  1510.         }
  1511.         
  1512.         if (hitItem == 1) {
  1513.             /* and one more switch, pull parameters and create the actual data descriptor that */
  1514.             /* we will pass along in the SetData event. */
  1515.             /* ••here•• */
  1516.             /* pull the various parameters for the data to set, create a Desc to hold them, */
  1517.             /* and add that desc to our event */
  1518.             switch (which) {
  1519.                 Str255 tempString;
  1520.                 long theNum;
  1521.                 register qq;
  1522.                 case kWindowBoundsItem:
  1523.                     theDataDesc = typeQDRectangle;
  1524.                     /* ugg.  Go through all the edit lines and make a rect  */
  1525.                     SetHandleSize(theDataHandle, sizeof(Rect));
  1526.                     tempShortPtr = (short *)*theDataHandle;
  1527.                     HLock(theDataHandle);
  1528.                     for (qq = kRectEdit1; qq < kRectEdit4 + 1; qq++) {
  1529.                         GetDialogItemText((Handle)SnatchHandle(tdial, qq), tempString);
  1530.                         StringToNum(tempString, &theNum);
  1531.                         *tempShortPtr = theNum;
  1532.                         tempShortPtr = tempShortPtr + 1;        /* I have had problems with MPW C dealing with a += on a pointer, so I don't do it */
  1533.                     }
  1534.                     break;
  1535.                 case kWindowTitleItem:
  1536.                     theDataDesc = typeChar;
  1537.                     GetDialogItemText((Handle)SnatchHandle(tdial, kNewTitleEditLineItem), tempString);
  1538.                     SetHandleSize(theDataHandle, tempString[0]);
  1539.                     /* move the text into the handle */
  1540.                     HLock(theDataHandle);
  1541.                     BlockMove((Ptr)&tempString[1], (Ptr)*theDataHandle, tempString[0]);
  1542.                     /* leave the data handle locked for later */
  1543.                     break;
  1544.                 case kWindowVisiblityItem:
  1545.                     theDataDesc = typeBoolean;
  1546.                     doVis = GetControlValue(SnatchHandle(tdial, kMakeVisItem));
  1547.                     SetHandleSize(theDataHandle, sizeof(short));        /* a boolean is short length */
  1548.                     HLock(theDataHandle);                   /* for later */
  1549.                     tempShortPtr = (short *)*theDataHandle;
  1550.                     *tempShortPtr = (doVis ? -1 : false);
  1551.                     break;
  1552.                 case kAllText:
  1553.                 case kWordText:
  1554.                     /* these are both the same */
  1555.                     theDataDesc = typeChar;
  1556.                     GetDialogItemText((Handle)SnatchHandle(tdial, kNewText), tempString);
  1557.                     SetHandleSize(theDataHandle, tempString[0]);
  1558.                     /* move the text into the handle */
  1559.                     HLock(theDataHandle);
  1560.                     BlockMove((Ptr)&tempString[1], (Ptr)*theDataHandle, tempString[0]);
  1561.                     
  1562.                     break;
  1563.                 case kShapeItem:
  1564.                 /* make the parameters for the shape change */
  1565.                 if(GetControlValue(SnatchHandle(tdial, kNewSColorRadio))){
  1566.                 /* setting color, the color is in newColor */
  1567.                                     theDataDesc = typeRGBColor;
  1568.                     SetHandleSize(theDataHandle, sizeof(RGBColor));
  1569.                     HLock(theDataHandle);
  1570.                     BlockMove((Ptr)&newColor,*theDataHandle,sizeof(RGBColor));
  1571.  
  1572.                 } else {
  1573.                 /* setting rect, same stuff as window  */
  1574.                                     theDataDesc = typeQDRectangle;
  1575.                     SetHandleSize(theDataHandle, sizeof(Rect));
  1576.                     tempShortPtr = (short *)*theDataHandle;
  1577.                     HLock(theDataHandle);
  1578.                     for (qq = kRectEdit1; qq < kRectEdit4 + 1; qq++) {
  1579.                         GetDialogItemText((Handle)SnatchHandle(tdial, qq), tempString);
  1580.                         StringToNum(tempString, &theNum);
  1581.                         *tempShortPtr = theNum;
  1582.                         tempShortPtr = tempShortPtr + 1;        /* I have had problems with MPW C dealing with a += on a pointer, so I don't do it */
  1583.                     }
  1584.  
  1585.  
  1586.  
  1587.                 }
  1588.                 AddShapeProperty(&object,GetControlValue(SnatchHandle(tdial, kNewSColorRadio)));
  1589.                     break;
  1590.             }
  1591.         } else {
  1592.             myErr = userCanceledErr;
  1593.         }
  1594.         DisposeDialog(tdial);
  1595.         /* dialog is gone, the data we want is in theDataHandle, the descriptor type is in theDataDesc, */
  1596.         /* it's time to put the data on the event. */
  1597.         /* create a desc to hold it */
  1598.         if (hitItem == 1) {
  1599.             /* put the object into the event now */
  1600.             myErr = AEPutParamDesc(thisEvent, keyDirectObject, &object);
  1601.             AEDisposeDesc(&object);
  1602.  
  1603.             
  1604.             
  1605.             myErr = AECreateDesc(theDataDesc, (Ptr)*theDataHandle, GetHandleSize(theDataHandle), &dataToSet);
  1606.             DisposeHandle(theDataHandle);                    /* don't need this anymore */
  1607.             if (!myErr) {
  1608.                 /* the desc created fine.  Add this to the event */
  1609.                 myErr = AEPutParamDesc(thisEvent, keyAEData, &dataToSet);
  1610.                 myErr = AEDisposeDesc(&dataToSet);
  1611.                 /* and the event is all ready to be sent by the caller, so we return */
  1612.             }
  1613.         } else {
  1614.             myErr = userCanceledErr;
  1615.         }
  1616.     }
  1617.     return(myErr);
  1618. }
  1619.  
  1620. /* BuildFullObject builds an object specifier based on the parameters set in */
  1621. /* the object dialogs in this sample. */
  1622. OSErr BuildFullObject(AEDesc *object, short which)
  1623. {
  1624.     OSErr myErr = noErr;
  1625.     AEDesc tempDesc;
  1626.     AEDesc otherTemp;
  1627.     long number1 = 1;
  1628.     DescType Props[3] =  {
  1629.         pBounds, pName, pVisible
  1630.     };
  1631.     
  1632.     BuildWindowObject(object);
  1633.     switch (which) {
  1634.         /* we already have a window object, so for the first three, create a property desc and type */
  1635.         /* since we're only working with the properties of windows */
  1636.         case kWindowBoundsItem:
  1637.         case kWindowTitleItem:
  1638.         case kWindowVisiblityItem:
  1639.             AEDuplicateDesc(object, &otherTemp);
  1640.             myErr = AECreateDesc(typeType, (Ptr)&Props[which - 1], kFour, &tempDesc);
  1641.             myErr = CreateObjSpecifier(typeProperty, &otherTemp, formPropertyID, &tempDesc, true, object);
  1642.             
  1643.             break;
  1644.             
  1645.         case kAllText:
  1646.             /* we're asking for all the text in the window */
  1647.             AEDuplicateDesc(object, &otherTemp);
  1648.             HLock((Handle)gTextObjSpecHandle);
  1649.             if ((*gTextObjSpecHandle)->u.index == 0)
  1650.                 (*gTextObjSpecHandle)->u.index = 1;
  1651.             myErr = AECreateDesc(typeLongInteger, (Ptr)&(*gTextObjSpecHandle)->u.index, sizeof(long), &tempDesc);
  1652.             
  1653.             myErr = CreateObjSpecifier(cText, &otherTemp, formAbsolutePosition, &tempDesc, true, object);
  1654.             
  1655.             HUnlock((Handle)gTextObjSpecHandle);
  1656.             break;
  1657.         case kWordText:
  1658.             /* one word from the window and text object  */
  1659.             AEDuplicateDesc(object, &otherTemp);
  1660.             HLock((Handle)gTextObjSpecHandle);
  1661.             if ((*gTextObjSpecHandle)->u.index == 0)
  1662.                 (*gTextObjSpecHandle)->u.index = 1;
  1663.             myErr = AECreateDesc(typeLongInteger, (Ptr)&(*gTextObjSpecHandle)->u.index, sizeof(long), &tempDesc);
  1664.             
  1665.             myErr = CreateObjSpecifier(cText, &otherTemp, formAbsolutePosition, &tempDesc, true, object);
  1666.             AEDuplicateDesc(object, &otherTemp);
  1667.             if ((*gTextObjSpecHandle)->wordNumber == 0)
  1668.                 (*gTextObjSpecHandle)->wordNumber = 0;
  1669.             myErr = AECreateDesc(typeLongInteger, (Ptr)&(*gTextObjSpecHandle)->wordNumber, sizeof(long), &tempDesc);
  1670.             myErr = CreateObjSpecifier(cWord, &otherTemp, formAbsolutePosition, &tempDesc, true, object);
  1671.             
  1672.             HUnlock((Handle)gTextObjSpecHandle);
  1673.             break;
  1674.             /* for these, we have to add the additional cDrawingArea container */
  1675.         case kShapeItem:
  1676.             AEDuplicateDesc(object, &otherTemp);
  1677.             /* this always defaults to 1, we have only one drawing area per window */
  1678.             AECreateDesc(typeLongInteger, (Ptr)&number1, sizeof(long), &tempDesc);
  1679.             myErr = CreateObjSpecifier(cDrawingArea, &otherTemp, formAbsolutePosition, &tempDesc, true, object);
  1680.             /* now which the thing */
  1681.  
  1682.             myErr = CreateShapeObject(object);
  1683.             break;
  1684.     }
  1685.     mAEErrorDisplay("\p creating object", myErr)
  1686.     
  1687.     return(myErr);
  1688.     
  1689. }
  1690. /* BuildWindowObject builds a window object from null, based on the parameters you have */
  1691. /* specified in the dialog boxes */
  1692. OSErr BuildWindowObject(AEDesc *returnedObject)
  1693. {
  1694.     long theLong = 1;
  1695.     OSErr myErr = noErr;
  1696.     AEDesc containerDesc;
  1697.     AEDesc theIdentifier;
  1698.     /* establish some defaults so the object will be right even if the Window Object dialog hasn't been used */
  1699.     DescType theForm = formAbsolutePosition;
  1700.     long number1 = 1;
  1701.     HLock((Handle)gWindObjSpecHandle);
  1702.     switch ((*gWindObjSpecHandle)->form) {
  1703.         case formAbsolutePosition:
  1704.             theForm = formAbsolutePosition;
  1705.             /* make an abs for spec */
  1706.             /* What??  What that comment really meant, was create an object specifier for a window */
  1707.             /* based on the data we have stored in our window descriptor object, that's */
  1708.             /* set with the dialog, based on absolute position or name */
  1709.             if ((*gWindObjSpecHandle)->u.index == 0)
  1710.                 (*gWindObjSpecHandle)->u.index = 1;
  1711.             myErr = AECreateDesc(typeLongInteger, (Ptr)&(*gWindObjSpecHandle)->u.index, sizeof(long), &theIdentifier);
  1712.             
  1713.             break;
  1714.         case formName:
  1715.             /* make an object specifier based on window name */
  1716.             
  1717.             theForm = formName;
  1718.             myErr = AECreateDesc(typeChar, (Ptr)&(*gWindObjSpecHandle)->u.name[1], (*gWindObjSpecHandle)->u.name[0],
  1719.                                  &theIdentifier);
  1720.             break;
  1721.         default:
  1722.             /* defaults to a byindex, window one spec if nothing else has been set up */
  1723.             myErr = AECreateDesc(typeLongInteger, (Ptr)&number1, sizeof(long), &theIdentifier);
  1724.             break;
  1725.     }
  1726.     mAEErrorDisplay("\p creating formProperty for this thing", myErr)
  1727.     /* Every event will act on a window */
  1728.     
  1729.     /* we're always adding windows from nul, so duplicate nul */
  1730.     AEDuplicateDesc(&gNullDesc, &containerDesc);
  1731.     
  1732.     /* build a window object contained in nul */
  1733.     myErr = CreateObjSpecifier(cWindow, &containerDesc, theForm, &theIdentifier, true, returnedObject);
  1734.     mAEErrorDisplay("\p creating window object", myErr)
  1735.     HUnlock((Handle)gWindObjSpecHandle);
  1736.     return(myErr);
  1737. }
  1738.  
  1739. /* CreateShapeObject attached the shape object to the basic specifier */
  1740. /* already created (nul>cWindow>cDrawingArea) */
  1741. /* Since all my shapes are basically the same, we have one routine to do this for us */
  1742.  
  1743. OSErr CreateShapeObject(AEDesc *theContainer)
  1744. {
  1745.     AEDesc tempDesc;
  1746.     AEDesc indexDesc;
  1747.     DescType theType;
  1748.     OSErr myErr = noErr;
  1749.     HLock((Handle)gShapeObjSpecHandle);
  1750.     theType = (*gShapeObjSpecHandle)->form;
  1751.     /* duplicate what we have so far */
  1752.     AEDuplicateDesc(theContainer, &tempDesc);
  1753.     /* In this example, we're only implementing a ByIndex form for graphics, so... */
  1754.     if ((*gShapeObjSpecHandle)->u.index == 0)
  1755.         (*gShapeObjSpecHandle)->u.index = 1;
  1756.     myErr = AECreateDesc(typeLongInteger, (Ptr)&(*gShapeObjSpecHandle)->u.index, sizeof(long), &indexDesc);
  1757.     myErr = CreateObjSpecifier(theType, &tempDesc, formAbsolutePosition, &indexDesc, true, theContainer);
  1758.     HUnlock((Handle)gShapeObjSpecHandle);
  1759.     return(myErr);
  1760. }
  1761.  
  1762. /* AddShapeProperty tacks a property specifier onto an already created shape specifier */
  1763. OSErr AddShapeProperty(AEDesc *theObject,Boolean which)
  1764. {
  1765.     AEDesc tempDesc,otherTemp;
  1766.     DescType theProp;
  1767.     OSErr myErr = noErr;
  1768.     if(which)
  1769.         theProp = pPenColor;
  1770.     else
  1771.         theProp = pBounds;
  1772.     myErr = AEDuplicateDesc(theObject, &otherTemp);
  1773.     myErr |= AECreateDesc(typeType,(Ptr) &theProp, kFour, &tempDesc);
  1774.     myErr |= CreateObjSpecifier(typeProperty, &otherTemp, formPropertyID, &tempDesc, true, theObject);
  1775.     
  1776.     return(myErr);
  1777. }
  1778.  
  1779. #undef __AEOBJ__
  1780.